package org.linlinjava.litemall.core.exception;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.io.IOException;
import java.lang.reflect.Type;

/**
 * 增强全局异常解析转换,
 * Destin
 */
@Slf4j
@Component
public class JsonResponseErrorConverter extends MappingJackson2HttpMessageConverter {

    public JsonResponseErrorConverter(ObjectMapper objectMapper) {
        super(objectMapper);
    }

    @Override
    protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        handleException(inputMessage, null);
        return super.readInternal(clazz, inputMessage);
    }

    @Override
    public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        handleException(inputMessage, contextClass);
        return super.read(type, contextClass, inputMessage);
    }

    private void handleException(HttpInputMessage inputMessage, Class<?> contextClass) {
        if (inputMessage.getHeaders().containsKey(GlobalExceptionHandler.KEY_RESPONSE_ERROR_TYPE)) {
            Integer errorType = Integer.valueOf(inputMessage.getHeaders().get(GlobalExceptionHandler.KEY_RESPONSE_ERROR_TYPE).get(0));
            log.debug("Api response error type : {}", errorType);
            Result<?> result = null;
            try {
                result = (Result<?>) super.read(Result.class, contextClass, inputMessage);
            } catch (IOException e) {
                log.error("Handle remote exception error : {}", e.getMessage(), e);
            }
            if (BusinessException.ERROR_TYPE == errorType) {
                throw BusinessException.create(new WrapperCode(result.getCode()), result.getMessage())
                        .putAttribute("data", result.getData());
            }
        }
    }

    class WrapperCode implements ErrorCode {
        private int _code;

        WrapperCode(int code) {
            _code = code;
        }

        @Override
        public int getCode() {
            return _code;
        }
    }
}
